package smallfrench.moteur.interp;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import smallfrench.moteur.biblio.err.ExceptionInterruption;
import smallfrench.moteur.interp.err.RException;

/**
 * Joue un rôle similaire à l’Event Dispatcher Thread de Swing.
 * 
 * @author antoine1023
 *
 */
public class TacheEvenements extends Thread {

	private static class Evenement implements Evaluable {

		public final RObjet fonction;
		public final RObjet[] parametres;

		public Evenement(RObjet fonction, RObjet[] parametres) {
			this.fonction = fonction;
			this.parametres = parametres;
		}

		@Override
		public RObjet evaluer() {
			return fonction.appeler(null, parametres);
		}

		@Override
		public String toString() {
			return "Evenement";
		}
	}

	private BlockingQueue<Evenement> queue;

	private final ProcessusScript processusScript;

	/**
	 * <code>true</code> si un évenement est en cours.
	 */
	private boolean evenementEnCours;

	public TacheEvenements(ProcessusScript processusScript) {
		this.processusScript = processusScript;
		queue = new LinkedBlockingQueue<Evenement>();
	}

	/**
	 * Ajoute un évènement à la file.
	 * @param fonction
	 * @param parametres
	 */
	public void ajouterEvenement(RObjet fonction, RObjet[] parametres) {
		queue.add(new Evenement(fonction, parametres));
	}

	/**
	 * 
	 * @return <code>true</code> si tous les évènements ont été traités.
	 */
	public boolean estVide() {
		return queue.isEmpty();
	}

	/**
	 * 
	 * @param evenement
	 * @return La valeur de retour de l’évènement
	 * @throws InterruptedException
	 */
	private final RObjet evaluerEvenement(Evenement evenement)
			throws InterruptedException  {

		try {

			return evenement.evaluer();

		} catch (RException re) {
			if (re.estUne(ExceptionInterruption.CLASSE))
				throw new InterruptedException();
			processusScript.intercepterRException(re);
			throw new InterruptedException();

		} catch (RuntimeException re) {
			processusScript.intercepterRuntimeException(re);
			throw new InterruptedException();
		}
	}


	/**
	 * 
	 * @return <code>true</code> si un évenement est en cours d’exécution.
	 * Attention, le fait qu’il n’ait aucun évenement en cours d’exécution ne
	 * veut pas dire que le thread est mort.
	 */
	public synchronized boolean evenementEstEnCours() {
		return evenementEnCours;
	}

	public ProcessusScript getProcessusScript() {
		return processusScript;
	}

	@Override
	public void run() {

		for (;;) {

			try {
				Evenement e = queue.take();

				evenementEnCours = true;
				evaluerEvenement(e);
				evenementEnCours = false;

				//synchronized (this) {
				//	notify();
				//}

			} catch (InterruptedException e1) {
				break;
			}
		}
	}

}
